﻿#include <stddef.h>
#include <string>
#include <sstream>
#include <CXXLWCSPBRK.HPP>

using namespace CxxlMan;

// Constructor
cxxlWcspbrk::cxxlWcspbrk(const Smart_Ptr<IWcspbrkSource> &psts,ISpirit *spirit)
  :cxxlObject(spirit),Src(psts,this)
{

  unsigned int Buff_Len = 256;
  Buff_HalfLen = (Buff_Len >> 1);

  Buff_StrFs = 0;
  Buff_StrFsFlag = 0;
  pBuff = new wchar_t[Buff_Len];

  OverPoint = -1;

  size_t Len =
  Src->GetStr(pBuff,Buff_Len);

  if(Len < Buff_Len)
  {
    OverPoint = Len;
    pBuff[OverPoint] = L'\0';
  }
}

// Destructor
CxxlMan::cxxlWcspbrk::~cxxlWcspbrk()
{
  delete [] pBuff;
}

bool CxxlMan::cxxlWcspbrk::Compare(const wchar_t *Tok) const
{
  for(unsigned char StrFs = Buff_StrFs; StrFs != OverPoint && *Tok != L'\0'; ++StrFs,++Tok)
  {
    if(pBuff[StrFs] != *Tok)
      return false;
  }

  return true;
}

cxxlWcspbrk_Result cxxlFASTCALL CxxlMan::cxxlWcspbrk::Next(const wchar_t *tokens[])
{
  std::wostringstream Ret_Result;

  while(true)
  {
    if(isOver())
      return cxxlWcspbrk_Result(Ret_Result.str().c_str(),UNICODE_String());

    for(const wchar_t **Tok = tokens; *Tok != NULL; ++Tok)
    {
      if(Compare(*Tok))
      {
        UpdateStrFs(wcslen(*Tok));
        return cxxlWcspbrk_Result(Ret_Result.str().c_str(),UNICODE_String( *Tok ));
      }
    }

    Ret_Result << pBuff[Buff_StrFs];
    UpdateStrFs(1);
  }
}

cxxlWcspbrk_XResult cxxlFASTCALL CxxlMan::cxxlWcspbrk::XNext(const wchar_t *skips[])
{
  std::wostringstream Ret_Result;

  while(true)
  {
    if(isOver())
      return cxxlWcspbrk_XResult(Ret_Result.str().c_str(),true);

    const wchar_t **Skip;
    for(Skip = skips; *Skip != NULL; ++Skip)
    {
      if(Compare(*Skip))
      {
        UpdateStrFs(wcslen(*Skip));
        Ret_Result << *Skip;
        break;
      }
    }

    if(*Skip == NULL)
      return cxxlWcspbrk_XResult(Ret_Result.str().c_str(), false);
  }
}


void cxxlFASTCALL CxxlMan::cxxlWcspbrk::UpdateStrFs(unsigned int Shift)
{
  Buff_StrFs = Buff_StrFs + Shift;
  // RetValue += (long long)Shift;

  unsigned char Flag = Buff_StrFs / Buff_HalfLen;

  if(Flag != Buff_StrFsFlag)
  {
    size_t Len;

    Buff_StrFsFlag = Flag;
    if(Buff_StrFsFlag == 1)
    {
      Len = Src->GetStr(pBuff, Buff_HalfLen);
      if(Len < Buff_HalfLen && OverPoint == -1)
      {
        OverPoint = Len;
        pBuff[OverPoint] = L'\0';
      }
    }
    else
    {
      Len = Src->GetStr(pBuff+Buff_HalfLen, Buff_HalfLen);
      if(Len < Buff_HalfLen && OverPoint == -1)
      {
        OverPoint = Len + Buff_HalfLen;
        pBuff[OverPoint] = L'\0';
      }
    }
  }
}

bool cxxlFASTCALL CxxlMan::cxxlWcspbrk::isOver() const
{
  return Buff_StrFs == OverPoint;
}



/*********************************
** class UnicodeStr_Source
*********************************/

UnicodeStr_Source::UnicodeStr_Source(const UNICODE_String &StrSrc,ISpirit *spirit)
  :cxxlObject(spirit),IWcspbrkSource(spirit),m_StrSrc(StrSrc)
{
  StrSrcBase = 0;
}


size_t cxxlFASTCALL UnicodeStr_Source::GetStr(wchar_t *Dest,size_t Len)
{
  size_t l = m_StrSrc.StrLength() - StrSrcBase;

  if(l >= Len)
  {
    for(size_t i = 0; i<Len; ++i)
    {
      Dest[i] = ((const wchar_t*)m_StrSrc)[StrSrcBase + i];
    }
    StrSrcBase += Len;
    return Len;
  }
  else
  {
    for(size_t i = 0; i < l; ++i)
    {
      Dest[i] = ((const wchar_t*)m_StrSrc)[StrSrcBase + i];
    }
    StrSrcBase = m_StrSrc.StrLength();
    return l;
  }
}

/*********************************
** cxxlWcsReplace()
*********************************/

CXXL_DLLEXPORT UNICODE_String
cxxlFASTCALL CxxlMan::cxxlWcsReplace(const UNICODE_String &StrSrc,const wchar_t *Srch[],const wchar_t *Rplc[])
{
  cxxlWcspbrk StrTok(new UnicodeStr_Source(StrSrc));

  std::wostringstream Ret_Result; // 回報處理過後的字串

  while(true)
  {
    cxxlWcspbrk_Result r = StrTok.Next( Srch );

    Ret_Result << (const wchar_t*)r.SubStr;

    if(r.Token.isNULL()) // 已找完
    {
      return UNICODE_String(Ret_Result.str().c_str());
    }


    for(const wchar_t **Sh = Srch, **Rp = Rplc; true; ++Sh,++Rp)
    {
      if( r.Token == *Sh ) // 確定找到哪個搜尋字串
      {
        Ret_Result << *Rp; // 替換
        break;
      }
    }
  }
}
